/*
 * Copyright 2012 ITC Tsinghua University. All Rights Reserved.
 */
package cn.edu.tsinghua.cic.ccss.bo.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.apache.log4j.Logger;
import org.forten.core.dao.rdb.hibernate.HibernateDao;
import org.forten.core.dao.rdb.hibernate.QueryInfo;
import org.forten.core.dao.rdb.query.hql.order.Order;
import org.forten.core.dao.rdb.query.hql.statement.OrderBy;
import org.forten.core.dao.rdb.query.hql.statement.Select;
import org.forten.core.dao.rdb.query.parameter.Param;
import org.forten.core.dao.rdb.query.parameter.Type;
import org.forten.core.qo.QueryField.MatchType;
import org.forten.core.qo.QueryObject;
import org.forten.core.qo.QueryObjectHelper;
import org.forten.core.ro.DtoResultWithPageInfo;
import org.forten.core.ro.PageInfo;
import org.forten.mail.template.FreeMarkerBean;
import org.forten.utils.collection.ArrayUtil;
import org.forten.utils.collection.CollectionUtil;
import org.forten.utils.common.DateUtil;
import org.forten.utils.common.NumberUtil;
import org.forten.utils.common.StringUtil;
import org.forten.utils.security.TripletsDESUtil;
import org.forten.utils.system.BeanPropertyUtil;
import org.forten.utils.system.LogUtil;
import org.forten.utils.system.PropertiesFileReader;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.thcic.sms.client.SmsClient;

import cn.edu.tsinghua.cic.ccss.bo.CourseBo;
import cn.edu.tsinghua.cic.ccss.bo.SystemSettingBo;
import cn.edu.tsinghua.cic.ccss.dto.CourseDto;
import cn.edu.tsinghua.cic.ccss.dto.CourseDto4Export;
import cn.edu.tsinghua.cic.ccss.dto.CourseDto4Import;
import cn.edu.tsinghua.cic.ccss.dto.CourseDto4Save;
import cn.edu.tsinghua.cic.ccss.dto.SendMessageToCadreDto;
import cn.edu.tsinghua.cic.ccss.entity.Course;
import cn.edu.tsinghua.cic.ccss.qo.CourseQo;

/**
 * 
 * 
 * @author <a href="mailto:du_yi@bbn.cn">Duyi</a>
 * 
 * @since 2012-5-10
 */
@Service("courseBo")
public class CourseBoImpl implements CourseBo {
	private static Logger log = Logger.getLogger(CourseBoImpl.class);

	@Resource
	private HibernateDao hibernateDao;
	/*@Resource
	private CourseDaoImpl courseDao;*/
	@Resource(name = "systemSettingBo")
	private SystemSettingBo systemSettingBo;
	@Resource
	private FreeMarkerBean freeMarkerBean;

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.edu.tsinghua.cic.ccss.bo.CourseBo#loadCourseDto(java.lang.Long)
	 */
	@Override
	@Transactional
	public CourseDto loadCourseDto(Long id) {
		CourseDto dto = new CourseDto();
		Course entity = hibernateDao.load(Course.class, id);
		BeanPropertyUtil.copy(dto, entity);
		return dto;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cn.edu.tsinghua.cic.ccss.bo.CourseBo#doSave(cn.edu.tsinghua.cic.ccss.
	 * dto.CourseDto)
	 */
	@Override
	@Transactional
	public Long doSave(CourseDto4Save dto) {
		Course entity = new Course();
		BeanPropertyUtil.copy(entity, dto);
		entity.setNum(getCourseNum());
		// 计算选课结束时间
		Date teachTime = entity.getTeachTime();
		Date finalEndDate = getEndChooseTime(teachTime);
		entity.setEndTimeChoose(finalEndDate);

		return hibernateDao.save(entity);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cn.edu.tsinghua.cic.ccss.bo.CourseBo#doUpdate(cn.edu.tsinghua.cic.ccss
	 * .dto.CourseDto)
	 */
	@Override
	@Transactional
	public void doUpdate(CourseDto dto) {
		Course entity = this.hibernateDao.load(Course.class, dto.getId());
		BeanPropertyUtil.copy(entity, dto);
		hibernateDao.update(entity);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.edu.tsinghua.cic.ccss.bo.CourseBo#doBatchImport(java.util.List)
	 */
	@Override
	@Transactional
	public List<String> doBatchImport(List<CourseDto4Import> dtoList) {
		List<String> formatErrMsg = new ArrayList<String>();
		if (CollectionUtil.isEmpty(dtoList)) {
			formatErrMsg.add("导入数据为空");
			return formatErrMsg;
		}
		Course[] arr = new Course[dtoList.size()];
		long courseNum = NumberUtil.parseNumber(getCourseNum(), Long.class);
		LogUtil.info(log, "于%s准备导入课程信息数据",
				DateUtil.convertDateToString(new Date()));
		int i = 0;
		for (CourseDto4Import dto : dtoList) {
			String errMsg = getFormatErrorMsg(dto);
			if (StringUtil.hasText(errMsg)) {
				formatErrMsg.add("第" + (i + 2) + "行数据格式错误：" + errMsg);
				i++;
				continue;
			}
			Course entity = new Course();
			BeanPropertyUtil.copy(entity, dto);
			entity.setNum(Long.toString(courseNum));

			// 计算选课结束时间
			Date teachTime = entity.getTeachTime();
			Date finalEndDate = getEndChooseTime(teachTime);
			entity.setEndTimeChoose(finalEndDate);

			arr[i] = entity;
			courseNum++;
			i++;
		}
		if (!CollectionUtil.isEmpty(formatErrMsg)) {
			return formatErrMsg;
		}
		LogUtil.info(log, "于%s完成课程信息数据导入，共导入%d条数据",
				DateUtil.convertDateToString(new Date()), i);
		hibernateDao.save(arr);
		return formatErrMsg;
	}

	private Date getEndChooseTime(Date teachTime) {
		String teachDay = DateUtil.convertDateToString(teachTime,
				DateUtil.DATE_PATTERN);
		Date teachDate = DateUtil.convertStringToDate(teachDay,
				DateUtil.DATE_PATTERN);
		int dateInterval = systemSettingBo
				.getIntValue("SELECT_COURSE_END_DATE");
		Date endDate = DateUtil.calculateDate(teachDate, 0 - dateInterval,
				Calendar.DAY_OF_MONTH);
		Calendar cal = Calendar.getInstance();
		cal.setTime(endDate);
		Date finalEndDate = DateUtil.getCommonTime(cal.get(Calendar.YEAR),
				cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DATE), 0, 0, 0);
		return finalEndDate;
	}

	private String getFormatErrorMsg(CourseDto4Import dto) {
		StringBuilder sb = new StringBuilder();
		if (!StringUtil.hasText(dto.getName())) {
			sb.append("[课程名不可为空]");
		}
		if (!StringUtil.hasText(dto.getClassroom())) {
			sb.append("[上课地点不可为空]");
		}
		if (!StringUtil.hasText(dto.getTeacherName())) {
			sb.append("[任课老师不可为空]");
		}
		if (dto.getClassCapacity() <= 0) {
			sb.append("[课容量必须大于0]");
		}
		if (dto.getCredit() <= 0) {
			sb.append("[学时必须大于0]");
		}
		if (dto.getTeachTime().before(new Date())) {
			sb.append("[授课时间必须晚于当前时间]");
		}
		return sb.toString();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cn.edu.tsinghua.cic.ccss.bo.CourseBo#queryCourseDtoPage(cn.edu.tsinghua
	 * .cic.ccss.qo.CourseQo, int)
	 */
	/*@Override
	@Transactional(readOnly = true)
	public DtoResultWithPageInfo<CourseDto> queryCourseDtoPage(CourseQo qo,
			int page,String fieldName,boolean isAsc) {
		QueryInfo qi = QueryObjectHelper.buildQueryInfo(qo);
		qi.setSelect(Select.getCountSelect("id"));
		Long totalEntities = hibernateDao.getCount(qi);
		if (totalEntities == 0) {
			return new DtoResultWithPageInfo<CourseDto>(
					new ArrayList<CourseDto>(), null);
		}

		PageInfo pi = PageInfo
				.getInstance(page,
						systemSettingBo.getIntValue("DEFAULT_PAGE_SIZE"),
						totalEntities);
		if(isAsc){
			qi.setOrderby(OrderBy.getOrderBy(Order.asc(fieldName)));
		} else {
			qi.setOrderby(OrderBy.getOrderBy(Order.desc(fieldName)));
		}
		qi.setFirstResult(pi.getFirstResultNum());
		qi.setMaxResult(pi.getPageSize());
		qi.setPage(true);
		qi.setSelect(null);
		qi.setUseCache(true);

		List<Course> result = hibernateDao.findEntities(qi);
		List<CourseDto> dtoResult = new ArrayList<CourseDto>(result.size());
		for (Course entity : result) {
			CourseDto courseDto = new CourseDto();
			BeanPropertyUtil.copy(courseDto, entity);
			dtoResult.add(courseDto);
		}
		return new DtoResultWithPageInfo<CourseDto>(dtoResult, pi);
	}*/

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cn.edu.tsinghua.cic.ccss.bo.CourseBo#queryCourseDto4Selection(cn.edu.
	 * tsinghua.cic.ccss.qo.CourseQo4Selection)
	 */
	/*@Transactional
	public DtoResultWithPageInfo<CourseDto> queryCourseDto4Selection(
			CourseQo4Selection qo, int pageNo,String type) {
		List<Course> result = null;
		long total = 0;
		String hql = null;
		if("user".equals(type)){
			hql = "FROM Course WHERE to_date(:currTime,'yyyy/MM/dd HH24:MI') BETWEEN startTimeChoose AND endTimeChoose ";
		} else {
			hql = "FROM Course WHERE to_date(:currTime,'yyyy/MM/dd HH24:MI') BETWEEN startTimeChoose AND teachTime ";
		}
		String currTime = DateUtil.convertDateToString(new Date(), "yyyy/MM/dd HH:mm");
		String countHql = "SELECT count(id) " + hql;
		if (StringUtil.hasText(qo.getName())) {
			countHql = countHql + "AND name LIKE :name ";
			hql = hql + "AND name LIKE :name ";
		}
		if (StringUtil.hasText(qo.getTeacherName())) {
			countHql = countHql + "AND teacherName LIKE :teacherName ";
			hql = hql + "AND teacherName LIKE :teacherName ";
		}
		//时间段起始、终止查询时间不为空
		if(StringUtil.hasText(qo.getStart()) && StringUtil.hasText(qo.getEnd())){
			countHql = countHql + "AND teachTime BETWEEN to_date(:start,'yyyy/MM/dd HH24:MI') AND to_date(:end,'yyyy/MM/dd HH24:MI')";
			hql = hql + "AND teachTime BETWEEN to_date(:start,'yyyy/MM/dd HH24:MI') AND to_date(:end,'yyyy/MM/dd HH24:MI')";
		}
		//起始时间不为空格，终止时间为空
		if(StringUtil.hasText(qo.getStart()) && !StringUtil.hasLength(qo.getEnd())){
//			qo.setEnd(currTime);终止时间为空，默认为系统当前时间
			countHql = countHql + "AND teachTime BETWEEN to_date(:start,'yyyy/MM/dd HH24:MI') AND to_date(:end,'yyyy/MM/dd HH24:MI')";
			hql = hql + "AND teachTime BETWEEN to_date(:start,'yyyy/MM/dd HH24:MI') AND to_date(:currTime,'yyyy/MM/dd HH24:MI')";
		}
		hql = hql + "ORDER BY teachTime";
		//This time we need more conditions to judge for four arguments
		if (StringUtil.hasText(qo.getName())
				&& !StringUtil.hasText(qo.getTeacherName()) && !StringUtil.hasText(qo.getStart())) {
			total = courseDao.getCount(countHql,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("name", qo.getName()));
		} else if (!StringUtil.hasText(qo.getName())
				&& StringUtil.hasText(qo.getTeacherName()) && !StringUtil.hasText(qo.getStart())) {
			total = courseDao.getCount(
					countHql,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("teacherName",
							qo.getTeacherName()));
		} else if (StringUtil.hasText(qo.getName())
				&& StringUtil.hasText(qo.getTeacherName()) && !StringUtil.hasText(qo.getStart())) {
			total = courseDao.getCount(
					countHql,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("name", qo.getName()),
					Param.getDefaultVarcharParamForLike("teacherName",
							qo.getTeacherName()));
		} else if(StringUtil.hasText(qo.getName())
				&& StringUtil.hasText(qo.getTeacherName()) && StringUtil.hasText(qo.getStart())
				&& StringUtil.hasText(qo.getEnd()) ){
			total = courseDao.getCount(
					countHql, 
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("name", qo.getName()),
					Param.getDefaultVarcharParamForLike("teacherName", qo.getTeacherName()),
					Param.getCommonParam("start", qo.getStart(), Type.STRING),
					Param.getCommonParam("end", qo.getEnd(), Type.STRING));
		} else if(StringUtil.hasText(qo.getName())
				&& StringUtil.hasText(qo.getTeacherName()) && !StringUtil.hasText(qo.getStart())
				&& StringUtil.hasText(qo.getEnd()) ){
			total = courseDao.getCount(
					countHql, 
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("name", qo.getName()),
					Param.getDefaultVarcharParamForLike("teacherName", qo.getTeacherName()),
					Param.getCommonParam("start", qo.getStart(), Type.STRING),
					Param.getCommonParam("end", currTime, Type.STRING));
		} else if(!StringUtil.hasText(qo.getName()) && !StringUtil.hasText(qo.getTeacherName())
				 && StringUtil.hasText(qo.getStart()) && !StringUtil.hasText(qo.getEnd())){
			total = courseDao.getCount(countHql, 
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getCommonParam("start", qo.getStart(), Type.STRING),
					Param.getCommonParam("end", currTime, Type.STRING));
		} else if(!StringUtil.hasText(qo.getName()) && !StringUtil.hasText(qo.getTeacherName())
				 && StringUtil.hasText(qo.getStart()) && StringUtil.hasText(qo.getEnd())){
			total = courseDao.getCount(countHql, 
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getCommonParam("start", qo.getStart(), Type.STRING),
					Param.getCommonParam("end", qo.getEnd(), Type.STRING));
		} else {
			
			total = courseDao.getCount(countHql,
					Param.getCommonParam("currTime", currTime, Type.STRING));
		}

		PageInfo pi = PageInfo.getInstance(pageNo,
				systemSettingBo.getIntValue("DEFAULT_PAGE_SIZE"), total);

		if (StringUtil.hasText(qo.getName())
				&& !StringUtil.hasText(qo.getTeacherName()) && !StringUtil.hasText(qo.getStart())) {
			result = courseDao.findCourse(hql, pi,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("name", qo.getName()));
		} else if (!StringUtil.hasText(qo.getName())
				&& StringUtil.hasText(qo.getTeacherName()) && !StringUtil.hasText(qo.getStart())) {
			result = courseDao.findCourse(
					hql,
					pi,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("teacherName",
							qo.getTeacherName()));
		} else if (StringUtil.hasText(qo.getName())
				&& StringUtil.hasText(qo.getTeacherName()) && !StringUtil.hasText(qo.getStart())) {
			result = courseDao.findCourse(
					hql,
					pi,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("name", qo.getName()),
					Param.getDefaultVarcharParamForLike("teacherName",
							qo.getTeacherName()));
		} else if (StringUtil.hasText(qo.getName())
				&& StringUtil.hasText(qo.getTeacherName()) && StringUtil.hasText(qo.getStart()) && StringUtil.hasText(qo.getEnd())) {
			result = courseDao.findCourse(
					hql,
					pi,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("name", qo.getName()),
					Param.getDefaultVarcharParamForLike("teacherName",
							qo.getTeacherName()),
					Param.getCommonParam("start", qo.getStart(), Type.STRING),
					Param.getCommonParam("end", qo.getEnd(), Type.STRING));
		} else if (StringUtil.hasText(qo.getName())
				&& StringUtil.hasText(qo.getTeacherName()) && StringUtil.hasText(qo.getStart()) && !StringUtil.hasText(qo.getEnd())) {
			//TODO 不确定因素
			result = courseDao.findCourse(
					hql,
					pi,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getDefaultVarcharParamForLike("name", qo.getName()),
					Param.getDefaultVarcharParamForLike("teacherName",
							qo.getTeacherName()),
					Param.getCommonParam("start", qo.getStart(), Type.STRING),
					Param.getCommonParam("end", currTime, Type.STRING));
		} else if (!StringUtil.hasText(qo.getName())
				&& !StringUtil.hasText(qo.getTeacherName()) && StringUtil.hasText(qo.getStart()) && !StringUtil.hasText(qo.getEnd())) {
			result = courseDao.findCourse(
					hql,
					pi,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getCommonParam("start", qo.getStart(), Type.STRING),
					Param.getCommonParam("end", currTime, Type.STRING));
		} else if (!StringUtil.hasText(qo.getName())
				&& !StringUtil.hasText(qo.getTeacherName()) && StringUtil.hasText(qo.getStart()) && StringUtil.hasText(qo.getEnd())) {
			result = courseDao.findCourse(
					hql,
					pi,
					Param.getCommonParam("currTime", currTime, Type.STRING),
					Param.getCommonParam("start", qo.getStart(), Type.STRING),
					Param.getCommonParam("end", qo.getEnd(), Type.STRING));
		} else {
			result = courseDao.findCourse(hql, pi,
					Param.getCommonParam("currTime", currTime, Type.STRING));
		}

		if (CollectionUtil.isEmpty(result)) {
			return new DtoResultWithPageInfo<CourseDto>(
					new ArrayList<CourseDto>(), null);
		}

		List<CourseDto> dtoResult = new ArrayList<CourseDto>(result.size());
		for (Course entity : result) {
			CourseDto courseDto = new CourseDto();
			BeanPropertyUtil.copy(courseDto, entity);
			dtoResult.add(courseDto);
		}
		return new DtoResultWithPageInfo<CourseDto>(dtoResult, pi);
	}
*/
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cn.edu.tsinghua.cic.ccss.bo.CourseBo#export(cn.edu.tsinghua.cic.ccss.
	 * qo.CourseQo)
	 */
	@Override
	@Transactional
	public List<CourseDto4Export> export(CourseQo qo) {
		QueryInfo qi = QueryObjectHelper.buildQueryInfo(qo);
		List<Course> result = hibernateDao.findEntities(qi);
		if (CollectionUtil.isEmpty(result)) {
			return new ArrayList<CourseDto4Export>();
		}

		List<CourseDto4Export> dtoResult = new ArrayList<CourseDto4Export>(
				result.size());
		for (Course entity : result) {
			CourseDto4Export courseDto = new CourseDto4Export();
			BeanPropertyUtil.copy(courseDto, entity);
			dtoResult.add(courseDto);
		}
		return dtoResult;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.edu.tsinghua.cic.ccss.bo.CourseBo#doDelete(java.lang.Long)
	 */
	@Override
	@Transactional
	public void doDelete(Long id) {
		Course entity = hibernateDao.load(Course.class, id);
		hibernateDao.delete(entity);
		String hql = "DELETE FROM CourseSelection where courseId=:id";
		hibernateDao.executeUpdate(hql,
				Param.getCommonParam("id", id, Type.LONG));
		hql = "DELETE FROM CourseCanceled where courseId=:id";
		hibernateDao.executeUpdate(hql,
				Param.getCommonParam("id", id, Type.LONG));
	}

	// 计算课程号
	private synchronized String getCourseNum() {
		String dateStr = DateUtil.convertDateToString(new Date(), "yyyyMMdd");

		String hql = "SELECT max(num) FROM Course WHERE num like :num";
		String result = hibernateDao.findCommonObject(hql, Param
				.getVarcharParamForLike("num", dateStr, true, MatchType.START));
		if (!StringUtil.hasText(result)) {
			return dateStr + "001";
		}
		return "" + (NumberUtil.parseNumber(result, Long.class) + 1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.edu.tsinghua.cic.ccss.bo.CourseBo#querySendMailToCadreDto()
	 */
	@Override
	@Transactional
	public List<SendMessageToCadreDto> querySendMailToCadreDto() {
		List<SendMessageToCadreDto> resultList = new ArrayList<SendMessageToCadreDto>();

		String hql = "FROM Course WHERE endTimeChoose<=to_date(:currentTime,'yyyy/MM/dd HH24:MI') AND teachTime>=to_date(:currentTime,'yyyy/MM/dd HH24:MI') AND sendEmailFlag='0'";
		Date currDate = DateUtil.currentTime();
		List<Course> courseList = hibernateDao.findEntities(hql, false, Param
				.getCommonParam("currentTime", DateUtil.convertDateToString(
						currDate, "yyyy/MM/dd HH:mm"), Type.STRING));
		LogUtil.info(log, "满足条件即将发送邮件的课程数目是================ :%d", courseList.size());
		if (CollectionUtil.isEmpty(courseList)) {
			return new ArrayList<SendMessageToCadreDto>();
		}

		String getCadreIdHql = "SELECT cadreId FROM CourseSelection WHERE courseId=:courseId AND deletedCardNum='0'";
		String getCadreEmailHql = "SELECT email FROM Cadre WHERE id in (:cadreIds) AND email IS NOT NULL";
		for (Course course : courseList) {
			Long courseId = course.getId();
			Object[] cadreIds = hibernateDao.findObjectArray(getCadreIdHql,
					Param.getCommonParam("courseId", courseId, Type.LONG));
		LogUtil.info(log, "满足条件即将收到邮件的人数是================ :%d", cadreIds.length);	
			if (ArrayUtil.isEmpty(cadreIds)) {
				continue;
			}

			Object[] cadreEmails = hibernateDao.findObjectArray(
					getCadreEmailHql,
					Param.getCommonParam("cadreIds", cadreIds, Type.ARRAY));
			if (ArrayUtil.isEmpty(cadreEmails)) {
				continue;
			}

			for (int i = 0; i < cadreEmails.length; i++) {
				cadreEmails[i] = TripletsDESUtil.decrypt(systemSettingBo
						.getStringValue("CURRENT_TRIPLETS_DES_KEY"),
						(String) cadreEmails[i]);
			}

			// 排重
			cadreEmails = ArrayUtil.getWithoutDuplicatesArray(cadreEmails);

			String allEmail = StringUtils
					.arrayToCommaDelimitedString(cadreEmails);
			SendMessageToCadreDto dto = new SendMessageToCadreDto();
			BeanPropertyUtil.copy(dto, course);
			dto.setCurrentTime(DateUtil.convertDateToString(new Date(),
					"yyyy年MM月dd日"));
			dto.setTeachTimeStr(DateUtil.convertDateToString(
					dto.getTeachTime(), "yyyy年MM月dd日 HH时mm分"));
			dto.setCadreEmails(allEmail);
			resultList.add(dto);
		}

		Course[] courseArr = new Course[courseList.size()];
		int i = 0;
		for (Course course : courseList) {
			course.setSendEmailFlag("1");
			courseArr[i] = course;
			i++;
		}
		hibernateDao.update(courseArr);

		return resultList;
	}

	@Override
	@Transactional
	public List<SendMessageToCadreDto> querySendShortMessageToCadreDto() {
		List<SendMessageToCadreDto> resultList = new ArrayList<SendMessageToCadreDto>();
		
		
		Date curDate = DateUtil.currentTime();
		Date nextCurDate = DateUtil.calculateDate(curDate, 1, Calendar.DAY_OF_MONTH);
		String hql = "FROM Course WHERE teachTime<=to_date(:nextCurDate,'yyyy/MM/dd HH24:MI') AND teachTime>=to_date(:curDate,'yyyy/MM/dd HH24:MI') AND sendMessageFlag='0'";		
		List<Course> courseList = hibernateDao.findEntities(hql, false, 
				Param.getCommonParam("nextCurDate", DateUtil.convertDateToString(
						nextCurDate, "yyyy/MM/dd HH:mm"), Type.STRING),
						Param.getCommonParam("curDate", DateUtil.convertDateToString(
								curDate, "yyyy/MM/dd HH:mm"), Type.STRING)		);
		LogUtil.info(log, "满足条件即将发送短信的课程数目是============== :%d", courseList.size());
		if (CollectionUtil.isEmpty(courseList)) {
			return new ArrayList<SendMessageToCadreDto>();
		}

		String getCadreIdHql = "SELECT cadreId FROM CourseSelection WHERE courseId=:courseId AND deletedCardNum='0'";
		String getCadreMobileNumHql = "SELECT mobileNum FROM Cadre WHERE id in (:cadreIds) AND mobileNum IS NOT NULL";
		for (Course course : courseList) {
			Long courseId = course.getId();
			Object[] cadreIds = hibernateDao.findObjectArray(getCadreIdHql,
					Param.getCommonParam("courseId", courseId, Type.LONG));
		LogUtil.info(log, "满足条件即将收到短信的人数是================ :%d", cadreIds.length);	
			if (ArrayUtil.isEmpty(cadreIds)) {
				continue;
			}

			Object[] cadreMobileNums = hibernateDao.findObjectArray(
					getCadreMobileNumHql,
					Param.getCommonParam("cadreIds", cadreIds, Type.ARRAY));
			LogUtil.info(log, "满足条件即将收到短信的手机号码数是================ :%d", cadreMobileNums.length);
			if (ArrayUtil.isEmpty(cadreMobileNums)) {
				continue;
			}
			for (int i = 0; i < cadreMobileNums.length; i++) {
				cadreMobileNums[i] = TripletsDESUtil.decrypt(systemSettingBo
						.getStringValue("CURRENT_TRIPLETS_DES_KEY"),
						(String) cadreMobileNums[i]);
			}

			// 排重
			cadreMobileNums = ArrayUtil
					.getWithoutDuplicatesArray(cadreMobileNums);

			String allNums = StringUtils
					.arrayToCommaDelimitedString(cadreMobileNums);
//			allNums = allNums.substring(0, allNums.length() - 1);
			SendMessageToCadreDto dto = new SendMessageToCadreDto();
			BeanPropertyUtil.copy(dto, course);
			dto.setCadreMobileNums(allNums);
			dto.setTeachTimeStr(DateUtil.convertDateToString(
					dto.getTeachTime(), "yyyy年MM月dd日HH时mm分"));
			resultList.add(dto);
		}

		Course[] courseArr = new Course[courseList.size()];
		int i = 0;
		for (Course course : courseList) {
			course.setSendMessageFlag("1");
			courseArr[i] = course;
			i++;
		}
		hibernateDao.update(courseArr);

		return resultList;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cn.edu.tsinghua.cic.ccss.bo.CourseBo#getMailMessageToCadre(java.lang.
	 * Long)
	 */
	@Override
	@Transactional
	public String getMailMessageToCadre(Long courseId) throws AddressException {
		Course course = hibernateDao.load(Course.class, courseId);
		SendMessageToCadreDto dto = new SendMessageToCadreDto();
		BeanPropertyUtil.copy(dto, course);
		dto.setCurrentTime(DateUtil.convertDateToString(new Date(),
				"yyyy年MM月dd日"));
		dto.setTeachTimeStr(DateUtil.convertDateToString(dto.getTeachTime(),
				"yyyy年MM月dd日HH时mm分"));

		Map<String, SendMessageToCadreDto> data = new HashMap<String, SendMessageToCadreDto>();
		data.put("dto", dto);
		return freeMarkerBean.getTemplateContent("to_students_email.ftl", data);
	}

	@Override
	@Transactional
	public String getShortMessageToCadre(Long courseId) {
		Course course = hibernateDao.load(Course.class, courseId);
		SendMessageToCadreDto dto = new SendMessageToCadreDto();
		BeanPropertyUtil.copy(dto, course);
		dto.setTeachTimeStr(DateUtil.convertDateToString(dto.getTeachTime(),
				"yyyy年MM月dd日 HH时mm分"));

		Map<String, SendMessageToCadreDto> data = new HashMap<String, SendMessageToCadreDto>();
		data.put("dto", dto);
		return freeMarkerBean.getTemplateContent("to_students_sms.ftl", data);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.edu.tsinghua.cic.ccss.bo.CourseBo#sendMail(java.lang.Long,
	 * java.lang.String)
	 */
	@Override
	@Transactional
	public void sendMail(Long courseId, String msg) {
		Course course = hibernateDao.load(Course.class, courseId);
		String getCadreIdHql = "SELECT cadreId FROM CourseSelection WHERE courseId=:courseId AND deletedCardNum='0'";
		String getCadreEmailHql = "SELECT email FROM Cadre WHERE id in (:cadreIds) AND email IS NOT NULL";
		Object[] cadreIds = hibernateDao.findObjectArray(getCadreIdHql,
				Param.getCommonParam("courseId", courseId, Type.LONG));

		Object[] cadreEmails = null;
		if (ArrayUtil.isEmpty(cadreIds)) {
			LogUtil.warn(log, "发送开课通知邮件时未找到选择课程ID为%d课程的干部数据", courseId);
			return;
		} else {
			cadreEmails = hibernateDao.findObjectArray(getCadreEmailHql,
					Param.getCommonParam("cadreIds", cadreIds, Type.ARRAY));
		}
		if (ArrayUtil.isEmpty(cadreEmails)) {
			LogUtil.warn(log, "发送开课通知邮件时未找到选择课程ID为%d课程的干部Email地址", courseId);
			return;
		}
		for (int i = 0; i < cadreEmails.length; i++) {
			cadreEmails[i] = TripletsDESUtil.decrypt(
					systemSettingBo.getStringValue("CURRENT_TRIPLETS_DES_KEY"),
					(String) cadreEmails[i]);
		}

		// 排重
		cadreEmails = ArrayUtil.getWithoutDuplicatesArray(cadreEmails);

		String allEmail = StringUtils.arrayToCommaDelimitedString(cadreEmails);
		SendMessageToCadreDto dto = new SendMessageToCadreDto();
		BeanPropertyUtil.copy(dto, course);
		dto.setCadreEmails(allEmail);

		Email email = new HtmlEmail();
		email.setCharset("UTF-8");
		email.setHostName(systemSettingBo.getStringValue("EMAIL_HOST_NAME"));
		email.setAuthenticator(new DefaultAuthenticator(systemSettingBo
				.getStringValue("EMAIL_USERNAME"), systemSettingBo
				.getStringValue("EMAIL_PASSWORD")));
		try {
			email.setFrom(systemSettingBo.getStringValue("EMAIL_FROM"));
			email.setSubject(dto.getName() + "-开课通知");
			InternetAddress[] adds = InternetAddress
					.parse(dto.getCadreEmails());
			email.setTo(Arrays.asList(adds));
			Map<String, SendMessageToCadreDto> data = new HashMap<String, SendMessageToCadreDto>();
			data.put("dto", dto);
			email.setMsg(msg);

			email.send();
		} catch (EmailException e) {
			LogUtil.error(log, "邮件发送异常：%s", e.getMessage());
		} catch (AddressException e) {
			LogUtil.error(log, "邮件地址异常：%s", e.getMessage());
		}
	}

	@Override
	@Transactional
	public void sendShortMessage(Long courseId, String msg) {
		Course course = hibernateDao.load(Course.class, courseId);
		String getCadreIdHql = "SELECT cadreId FROM CourseSelection WHERE courseId=:courseId AND deletedCardNum='0'";
		String getCadreMobileNumHql = "SELECT mobileNum FROM Cadre WHERE id in (:cadreIds) AND mobileNum IS NOT NULL";
		Object[] cadreIds = hibernateDao.findObjectArray(getCadreIdHql,
				Param.getCommonParam("courseId", courseId, Type.LONG));

		Object[] mobileNums = null;
		if (ArrayUtil.isEmpty(cadreIds)) {
			LogUtil.warn(log, "发送开课通知短信时未找到选择课程ID为%d课程的干部数据", courseId);
			return;
		} else {
			mobileNums = hibernateDao.findObjectArray(getCadreMobileNumHql,
					Param.getCommonParam("cadreIds", cadreIds, Type.ARRAY));
		}
		if (ArrayUtil.isEmpty(mobileNums)) {
			LogUtil.warn(log, "发送开课通知短信时未找到选择课程ID为%d课程的干部手机号", courseId);
			return;
		}
		for (int i = 0; i < mobileNums.length; i++) {
			mobileNums[i] = TripletsDESUtil.decrypt(
					systemSettingBo.getStringValue("CURRENT_TRIPLETS_DES_KEY"),
					(String) mobileNums[i]);
		}

		// 排重
		mobileNums = ArrayUtil.getWithoutDuplicatesArray(mobileNums);

		String allMobileNums = StringUtils
				.arrayToCommaDelimitedString(mobileNums);
		SendMessageToCadreDto dto = new SendMessageToCadreDto();
		BeanPropertyUtil.copy(dto, course);
		dto.setCadreMobileNums(allMobileNums);

		String message = "";
		Map<String, SendMessageToCadreDto> data = new HashMap<String, SendMessageToCadreDto>();
		data.put("dto", dto);
		SmsClient.setServiceUrl(PropertiesFileReader.getValue("forten-system",
				"sms.url"));
		int code = SmsClient.sendMass(
				PropertiesFileReader.getValue("forten-system", "sms.appId"),
				PropertiesFileReader.getValue("forten-system", "sms.appKey"),
				dto.getCadreMobileNums(), msg);
		switch (code) {
		case 0:
			message = "SMS[0]:发送开课通知短信成功，success";
			break;
		case 10:
			message = "SMS[10]:调用参数错误，invokation param error";
			break;
		case 20:
			message = "SMS[20]:应用认证失败， auth error";
			break;
		case 900:
			message = "SMS[900]:数据库访问错误，DB access error";
			break;
		case 901:
			message = "SMS[901]:没有设置服务器URL地址，not setting server url address";
			break;
		case 902:
			message = "SMS[902]:连接服务器错误，server connection exception";
			break;
		default:
			break;
		}

		LogUtil.debug(log, message);
	}

	//TODO 新增Qo
	/*@Override
	@Transactional
	public DtoResultWithPageInfo<CourseDto> queryCourseDtoPage4Selection(
			CourseSelectAdminQo qo, int page, String fieldName, boolean isAsc) {
		QueryInfo qi = QueryObjectHelper.buildQueryInfo(qo);
		qi.setSelect(Select.getCountSelect("id"));
		Long totalEntities = hibernateDao.getCount(qi);
		if (totalEntities == 0) {
			return new DtoResultWithPageInfo<CourseDto>(
					new ArrayList<CourseDto>(), null);
		}

		PageInfo pi = PageInfo
				.getInstance(page,
						systemSettingBo.getIntValue("DEFAULT_PAGE_SIZE"),
						totalEntities);
		if(isAsc){
			qi.setOrderby(OrderBy.getOrderBy(Order.asc(fieldName)));
		} else {
			qi.setOrderby(OrderBy.getOrderBy(Order.desc(fieldName)));
		}
		qi.setFirstResult(pi.getFirstResultNum());
		qi.setMaxResult(pi.getPageSize());
		qi.setPage(true);
		qi.setSelect(null);
		qi.setUseCache(true);

		List<Course> result = hibernateDao.findEntities(qi);
		List<CourseDto> dtoResult = new ArrayList<CourseDto>(result.size());
		for (Course entity : result) {
			CourseDto courseDto = new CourseDto();
			BeanPropertyUtil.copy(courseDto, entity);
			dtoResult.add(courseDto);
		}
		return new DtoResultWithPageInfo<CourseDto>(dtoResult, pi);
	}*/
	
	/*//TODO 新增Qo
	@Override
	@Transactional
	public DtoResultWithPageInfo<CourseDto> queryCourseDtoPage4Selection(
			CourseSelectCadreQo qo, int page, String fieldName, boolean isAsc) {
		QueryInfo qi = QueryObjectHelper.buildQueryInfo(qo);
		qi.setSelect(Select.getCountSelect("id"));
		Long totalEntities = hibernateDao.getCount(qi);
		if (totalEntities == 0) {
			return new DtoResultWithPageInfo<CourseDto>(
					new ArrayList<CourseDto>(), null);
		}

		PageInfo pi = PageInfo
				.getInstance(page,
						systemSettingBo.getIntValue("DEFAULT_PAGE_SIZE"),
						totalEntities);
		if(isAsc){
			qi.setOrderby(OrderBy.getOrderBy(Order.asc(fieldName)));
		} else {
			qi.setOrderby(OrderBy.getOrderBy(Order.desc(fieldName)));
		}
		qi.setFirstResult(pi.getFirstResultNum());
		qi.setMaxResult(pi.getPageSize());
		qi.setPage(true);
		qi.setSelect(null);
		qi.setUseCache(true);

		List<Course> result = hibernateDao.findEntities(qi);
		List<CourseDto> dtoResult = new ArrayList<CourseDto>(result.size());
		for (Course entity : result) {
			CourseDto courseDto = new CourseDto();
			BeanPropertyUtil.copy(courseDto, entity);
			dtoResult.add(courseDto);
		}
		return new DtoResultWithPageInfo<CourseDto>(dtoResult, pi);
	}*/

	@Override
	@Transactional
	public <Q extends QueryObject> DtoResultWithPageInfo<CourseDto> queryCourseDtoPage(
			Q qo, int page, String fieldName, boolean isAsc) {
		QueryInfo qi = QueryObjectHelper.buildQueryInfo(qo);
		qi.setSelect(Select.getCountSelect("id"));
		Long totalEntities = hibernateDao.getCount(qi);
		if (totalEntities == 0) {
			return new DtoResultWithPageInfo<CourseDto>(
					new ArrayList<CourseDto>(), null);
		}

		PageInfo pi = PageInfo
				.getInstance(page,
						systemSettingBo.getIntValue("DEFAULT_PAGE_SIZE"),
						totalEntities);
		if(isAsc){
			qi.setOrderby(OrderBy.getOrderBy(Order.asc(fieldName)));
		} else {
			qi.setOrderby(OrderBy.getOrderBy(Order.desc(fieldName)));
		}
		qi.setFirstResult(pi.getFirstResultNum());
		qi.setMaxResult(pi.getPageSize());
		qi.setPage(true);
		qi.setSelect(null);
		qi.setUseCache(true);

		List<Course> result = hibernateDao.findEntities(qi);
		List<CourseDto> dtoResult = new ArrayList<CourseDto>(result.size());
		for (Course entity : result) {
			CourseDto courseDto = new CourseDto();
			BeanPropertyUtil.copy(courseDto, entity);
			dtoResult.add(courseDto);
		}
		return new DtoResultWithPageInfo<CourseDto>(dtoResult, pi);
	}
	
}